-- oUF_HealComm4
-- C J Silverio, ceejceej@gmail.com
-- http://code.google.com/p/leafedmods/
--
-- Conforms to oUF_HealComm behavior: 
-- 		set frame.ignoreHealComm to turn off the display for that frame
--		will not show the frame if the unit's max hp is unknown
--  New behaviors:
--		if frame.Health.invert is set, will flip the incoming heal bar
--		handles vertical health bars
--		colors can be overridden by setting frame.Health.incomingHealColors

if not oUF then return end

local healCommLibrary = LibStub("LibHealComm-4.0")
local IncomingHealHooks = {}
local playerName = UnitName("player")
local playerHeals = 0
local playerTarget = ""

local colors =
{
	normal = 
	{
		r = 0,
		g = 1,
		b = 0,
		a = .75,
	},
	inverted = 
	{
		r = 1,
		g = 1,
		b = 1,
		a = .75,
	},
	overheal = 
	{
		r = 1,
		g = 1,
		b = 0,
		a = .75,
	},
}

local getBarColor = function(frame, overhealing)
	-- TODO frames should be able to override all colors
	local incomingHealColor = colors.normal
	if frame.Health.incomingHealColors then
		incomingHealColor = frame.incomingHealColors
	elseif overhealing then
		incomingHealColor = colors.overheal
	elseif frame.Health.invert then
		incomingHealColor = colors.inverted
	end
	
	return incomingHealColor
end

-- ------------------------------------------------------------------------
-- Update a single bar.
-- ------------------------------------------------------------------------

local updateHealCommBar = function(frame, unit, unitGUID)
	if (not unit) then return end
	if (not frame.HealCommBar) then return end
	if (frame.ignoreHealComm) then return end

	local curHP = UnitHealth(unit)
	local maxHP = UnitHealthMax(unit)

	-- hide if we don't know this unit's max hp
	if ((maxHP == curHP) and (maxHP == 0)) then
		frame.HealCommBar:Hide()
		return
	end

	local incoming = 0
	local incoming = (healCommLibrary:GetHealAmount(unitGUID, healCommLibrary.ALL_HEALS) 
			or 0) * healCommLibrary:GetHealModifier(unitGUID)
	
	if (incoming <= 0) then
		frame.HealCommBar:Hide()
		return
	end
	
	-- Restrict how much overheal we show to avoid drawing bars halfway across the screen.
	local col = getBarColor(frame, false)
	if (incoming + curHP) > maxHP then
		col = getBarColor(frame, true)
		incoming = maxHP - curHP + 20 -- TODO magic number
	end
	frame.HealCommBar:SetStatusBarColor(col.r, col.g, col.b, col.a)

	frame.HealCommBar:Show()	

	local incomingWidth = frame.Health:GetWidth() * incoming / maxHP
	frame.HealCommBar:SetWidth(incomingWidth)
	frame.HealCommBar:SetHeight(frame.Health:GetHeight())
	
	-- TODO test this
	local anchorPoint = "LEFT"
	if (frame.Health:GetOrientation() == "VERTICAL") then
		anchorPoint = "TOP"
	end

	if (frame.Health.invert) then
		local healthBarRightEdge = frame.Health:GetWidth() * (maxHP - curHP) / maxHP
		frame.HealCommBar:SetPoint(anchorPoint, frame.Health, anchorPoint, healthBarRightEdge - incomingWidth, 0)
	else
		local healthBarRightEdge = frame.Health:GetWidth() * curHP / maxHP
		frame.HealCommBar:SetPoint(anchorPoint, frame.Health, anchorPoint, healthBarRightEdge, 0)
	end
end

-- ------------------------------------------------------------------------
-- All roads lead to the function that updates all bars.
-- ------------------------------------------------------------------------
local updateAllHealthBars = function(casterGUID, spellID, spellType, endTime, ...)
	local guidMap = healCommLibrary:GetGUIDUnitMapTable()

	for i = 1, select("#", ...) do
		local targetGUID = select(i, ...)
		if not guidMap[targetGUID] then return end
		local unit = UnitName(guidMap[targetGUID])

		for frame in pairs(oUF.units) do
			local fguid = UnitGUID(frame)
			if targetGUID == fguid then
				updateHealCommBar(oUF.units[frame], unit, targetGUID)
			end
		end
	end
end

-- ------------------------------------------------------------------------
-- Decorate an existing health bar with an incoming heals indication.
-- ------------------------------------------------------------------------
local function addIncomingHealBar(frame)
	if (frame.ignoreHealComm) then return end
	
	local incomingHealColor = getBarColor(frame, false)

	local hcb = CreateFrame("StatusBar")
	hcb:SetHeight(frame.Health:GetHeight())
	hcb:SetWidth(0)
	hcb:SetStatusBarTexture(frame.Health:GetStatusBarTexture():GetTexture())
	hcb:SetStatusBarColor(incomingHealColor.r, incomingHealColor.g, incomingHealColor.b, incomingHealColor.a)
	hcb:SetParent(frame)
	
	hcb:SetPoint("LEFT", frame.Health, "LEFT")
	
	hcb:Hide()
	frame.HealCommBar = hcb

	-- snag any existing post-update function and call it before we do our work
	local o = frame.PostUpdateHealth
	frame.PostUpdateHealth = function(...)
		if o then o(...) end
		local name, server = UnitName(frame.unit)
		if server then name = strjoin("-",name,server) end
		updateHealCommBar(frame, name, UnitGUID(frame.unit)) 
	end
end

-- ------------------------------------------------------------------------
-- Set up LibHealComm callbacks.
-- TODO do I really need different hooks? 
-- ------------------------------------------------------------------------
function IncomingHealHooks:HealStarted(event, casterGUID, spellID, spellType, endTime, ...)
	updateAllHealthBars(casterGUID, spellID, spellType, endTime, ...)
end

function IncomingHealHooks:HealUpdated(event, casterGUID, spellID, spellType, data, ...)
	updateAllHealthBars(casterGUID, spellID, spellType, data, ...)
end

function IncomingHealHooks:HealStopped(event, casterGUID, spellID, spellType, interrupted, ...)
	updateAllHealthBars(casterGUID, spellID, spellType, data, ...)
end

healCommLibrary.RegisterCallback(IncomingHealHooks, "HealComm_HealStarted", "HealStarted")
healCommLibrary.RegisterCallback(IncomingHealHooks, "HealComm_HealUpdated", "HealUpdated")
healCommLibrary.RegisterCallback(IncomingHealHooks, "HealComm_HealStopped", "HealStopped")
healCommLibrary.RegisterCallback(IncomingHealHooks, "HealComm_HealDelayed", "HealUpdated")
healCommLibrary.RegisterCallback(IncomingHealHooks, "HealComm_ModifierChanged", "HealUpdated")
healCommLibrary.RegisterCallback(IncomingHealHooks, "HealComm_GUIDDisappeared", "HealUpdated")

-- add the bar to all existing frames
for i, frame in ipairs(oUF.objects) do addIncomingHealBar(frame) end

-- and register to be added to new frames as they appear
oUF:RegisterInitCallback(addIncomingHealBar)
